//********************************************************************************
//
// File :           ph01_calc_pi_cluster.cpp
//
// Description :    calculate pi using cluster
//
// Dependencies:    mpi.h
//
// Author :         UlMonkey1987( WU Kan )
//
// Stu NO. :        2010212404
//
// Date :           2011-3-22
//
//********************************************************************************

#include "mpi.h"

#include <iostream>
#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <fstream>
#include <string>

using namespace std;

// double calcF( const double x )
double calcF( const double x )
{
    return ( 4.0 / ( 1.0 + x * x ) );
}
//

int main( int argc, char* argv[] )
{
    if ( argc < 3 )
    {
        cout << "error : lack args." << endl;
        cout << "usage : " << "<program_name>" << " <n> <output_file_path>." << endl;
        return 1;
    }

    const int MAX_PROC_NAME_LEN = 256;      // max length of a processor name

    int procN;                           // number of process
    int curProcId;                          // id of current process
    char curProcName[MAX_PROC_NAME_LEN];      // name of current process
    int curProcNameLen;                     // the length of current process name

    MPI_Init( &argc, &argv );
    MPI_Comm_size( MPI_COMM_WORLD, &procN );
    MPI_Comm_rank( MPI_COMM_WORLD, &curProcId );
    MPI_Get_processor_name( curProcName, &curProcNameLen );

    cout << "Process " << curProcId << " Running..." << endl << endl;

    long long int n = atoi( argv[1] );      // n
    string strOutPath = string( argv[2] );      // output path
    double finalPi;                         //  final result
    double tSum = 0;                        // temp sum
    double finalSum = 0;                    // final sum

    double timeStart, timeEnd, timeCost;        // start time, end time, duration time

    if ( 0 == curProcId )
        timeStart = MPI_Wtime();
    
    MPI_Bcast( &n, 1, MPI_INT, 0, MPI_COMM_WORLD );

    for ( long long int i = curProcId + 1; i <= n; i += procN )
    {
        tSum += calcF( ( i - 0.5 ) * 1.0 / n );
    }

    MPI_Reduce( &tSum, &finalSum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD );

    if ( 0 == curProcId )
    {
        timeEnd = MPI_Wtime();
        timeCost = timeEnd - timeStart;

        finalPi = finalSum * 1.0 / n;

        ofstream fout( strOutPath.c_str(), ios::app );

        fout << "cluster\t" << n << "\t" << procN << "\t" << setprecision( 20 ) << finalPi << "\t" << setprecision( 6 ) << abs( finalPi - acos( -1.0 ) ) << "\t" << timeCost << "\n";

        //cout << "Calculation Result : PI = " << setprecision( 20 ) << finalPi << endl << endl;

        //cout << "Time Consumed : " << setprecision( 6 ) << timeCost << " Ms" << endl << endl;
    }

    MPI_Finalize();

    return 0;
}


